package logger

import (
	"io"
	"os"
	"sync"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// Log 外部使用
var Log = NewZapLogger(defaultLogConfig)
var lock = sync.Mutex{}

// Writer 便于其他框架集成
var Writer io.Writer

type zapWriter struct {
	enableConsole bool
	writer        io.Writer
}

func newZapWriter(w io.Writer, console bool) *zapWriter {
	return &zapWriter{
		enableConsole: console,
		writer:        w,
	}
}

func (z *zapWriter) Write(p []byte) (n int, err error) {
	if !z.enableConsole {
		return z.writer.Write(p)
	}
	pCopy := make([]byte, len(p))
	copy(pCopy, p)
	go z.writeToConsole(pCopy)
	return z.writer.Write(p)
}

func (z *zapWriter) writeToConsole(bts []byte) {
	_, _ = os.Stdout.Write(bts)
}

// LogConfig 日志配置类
type LogConfig struct {
	Filename      string
	MaxSize       int
	MaxAge        int
	MaxBackups    int
	LocalTime     bool
	Compress      bool
	Level         string
	EnableConsole bool
}

// 默认日志配置
var defaultLogConfig = &LogConfig{
	Filename:      "logs/app.log",
	MaxSize:       10,
	MaxAge:        30,
	MaxBackups:    100,
	LocalTime:     true,
	Compress:      true,
	Level:         "debug",
	EnableConsole: true,
}

func fileWriter(cfg *LogConfig) io.Writer {
	writer := &lumberjack.Logger{}
	// 日志名称
	writer.Filename = cfg.Filename
	// 日志大小限制，单位MB
	writer.MaxSize = cfg.MaxSize
	// 历史日志文件保留天数
	writer.MaxAge = cfg.MaxAge
	// 最大保留历史日志数量
	writer.MaxBackups = cfg.MaxBackups
	// 本地时区
	writer.LocalTime = cfg.LocalTime
	// 历史日志文件压缩标识
	writer.Compress = cfg.Compress
	return writer
}

func getLogLevel(l string) zapcore.Level {
	switch l {
	case "debug", "DEBUG":
		return zapcore.DebugLevel
	case "info", "INFO", "": // make the zero value useful
		return zapcore.InfoLevel
	case "warn", "WARN":
		return zapcore.WarnLevel
	case "error", "ERROR":
		return zapcore.ErrorLevel
	case "dpanic", "DPANIC":
		return zapcore.DPanicLevel
	case "panic", "PANIC":
		return zapcore.PanicLevel
	case "fatal", "FATAL":
		return zapcore.FatalLevel
	default:
		return zapcore.DebugLevel
	}
}

func NewZapLogger(logConfig *LogConfig) *zap.SugaredLogger {

	var zapLog *zap.SugaredLogger

	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder   // 修改时间戳的格式
	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder // 日志级别使用大写显示
	encoder := zapcore.NewConsoleEncoder(encoderConfig)

	l := zap.NewAtomicLevelAt(getLogLevel(logConfig.Level))
	Writer = newZapWriter(fileWriter(logConfig), logConfig.EnableConsole)
	core := zapcore.NewCore(encoder, zapcore.AddSync(Writer), l) // 将日志级别设置为 DEBUG
	log := zap.New(core, zap.AddCaller())
	log = log.WithOptions(zap.AddCallerSkip(0))
	zapLog = log.Sugar()

	return zapLog
}

func SetLogger(logger *zap.SugaredLogger) {
	lock.Lock()
	defer lock.Unlock()
	Log = logger
}
